package com.foohoo.benchmark.exception;

import lombok.extern.slf4j.Slf4j;
import org.openjdk.jmh.annotations.*;

import java.util.concurrent.TimeUnit;

/**
 * 测试Exception.fillInStackTrace对性能的影响
 * @see Exception#fillInStackTrace()
 * Benchmark                                          Mode  Cnt   Score    Error  Units
 * FillInStackTrace.exceptionWithFillInStackTrace     avgt    3  21.692 ± 84.021  us/op
 * FillInStackTrace.exceptionWithoutFillInStackTrace  avgt    3   0.551 ±  2.967  us/op
 * 一句话结论: fillInStackTrace因为要调用原生方法爬方法调用栈，要多花约20微秒的时间，整体效率低约40倍
 *
 * @author mzdbxqh
 * @date 2020-10-19 10:34
 **/
@Slf4j
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@Warmup(iterations = 1, time = 1)
@Measurement(iterations = 3, time = 1)
@Fork(1)
@State(Scope.Benchmark)
@Threads(1)
public class FillInStackTrace {

	private static final int LOOP_TIME = 10;

	@Benchmark
	public void exceptionWithFillInStackTrace() {
		for (int i = 0; i < LOOP_TIME; i++) {
			try {
				throw new NormalException();
			} catch (Exception e) {
				// log.debug("catch normalException");
			}
		}
	}

	@Benchmark
	public void exceptionWithoutFillInStackTrace() {
		for (int i = 0; i < LOOP_TIME; i++) {
			try {
				throw new WithoutFillInStackTraceException();
			} catch (Exception e) {
				// log.debug("catch withoutFillInStackTraceException");
			}
		}
	}

	/**
	 * 普通异常类
	 */
	private static class NormalException extends RuntimeException {

	}

	/**
	 * 重写了fillInStackTrace方法，去掉了爬方法调用栈的异常类
	 */
	private static class WithoutFillInStackTraceException extends RuntimeException {
		/**
		 * 禁止调用原生的fillInStackTrace方法去爬堆栈
		 * 提升性能，同时丢失异常上下文的堆栈信息
		 * 便于将ServiceException用于业务流程控制
		 *
		 * @return {@link Throwable}
		 */
		@Override
		public synchronized Throwable fillInStackTrace() {
			return this;
		}
	}
}
